package com.example.studentdemo.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.example.studentdemo.entity.Account;
import com.example.studentdemo.service.AdminService;
import com.example.studentdemo.service.StudentService;
import com.example.studentdemo.service.TeacherService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Component
public class TokenUtils {

    @Resource
    AdminService adminService;
    @Resource
    TeacherService teacherService;
    @Resource
    StudentService studentService;
    @Resource
    RedisTemplate<String, Object> redisTemplate;

    static AdminService staticeAdminService;
    static TeacherService staticeTeacherService;
    static StudentService staticeStudentService;
    static RedisTemplate<String, Object> staticRedisTemplate;

    // springboot 工程启动后，会启动这段代码
    @PostConstruct
    public void init() {
        staticeAdminService = adminService;
        staticeTeacherService = teacherService;
        staticeStudentService = studentService;
        staticRedisTemplate = redisTemplate;
    }

    /**
     * 从Redis获取用户的token集合
     */
    private static Set<String> getUserTokens(String redisKey) {
        Set<String> userTokens = new HashSet<>();
        Object value = staticRedisTemplate.opsForValue().get(redisKey);
        if (value instanceof Set) {
            for (Object obj : (Set<?>) value) {
                if (obj instanceof String) {
                    userTokens.add((String) obj);
                }
            }
        }
        return userTokens;
    }

    /**
     * 生成token - 基于时间排序的设备登录数限制
     */
    public static String createToken(String userId, String role, String password, String deviceId) {
        String redisKey = "token:" + role + ":" + userId;

        // 使用LinkedHashSet保持插入顺序
        Set<String> userTokens = getUserTokens(redisKey);

        // 转换为列表以便处理
        List<String> tokenList = new ArrayList<>(userTokens);

        // 如果已达到设备上限（2个），移除最早的一个
        if (tokenList.size() >= 2) {
            // 移除第一个（最早添加的）
            String oldestToken = tokenList.get(0);
            userTokens.remove(oldestToken);
        }

        // 生成新token
        String token = JWT.create()
                .withAudience(userId + ":" + deviceId + ":" + role)
                .withExpiresAt(DateUtil.offsetDay(new Date(), 1))
                .sign(Algorithm.HMAC256(password));

        // 添加新token（会放在最后）
        userTokens.add(token);

        // 保存到Redis
        staticRedisTemplate.opsForValue().set(redisKey, userTokens, 1, TimeUnit.DAYS);

        return token;
    }

    /**
     * 验证token是否有效
     */
    public static boolean verifyToken(String token) {
        try {
            // 解析token
            String audience = JWT.decode(token).getAudience().get(0);
            String[] split = audience.split(":");
            String userId = split[0];
            @SuppressWarnings("unused")
            String deviceId = split[1];
            String role = split[2];

            // 获取用户信息
            Account account = null;
            if ("ADMIN".equals(role)) {
                account = staticeAdminService.selectById(Integer.valueOf(userId));
            } else if ("TEACHER".equals(role)) {
                account = staticeTeacherService.selectById(Integer.valueOf(userId));
            } else if ("STUDENT".equals(role)) {
                account = staticeStudentService.selectById(Integer.valueOf(userId));
            }

            if (account == null) {
                return true;
            }

            // 验证签名
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(account.getPassword())).build();
            jwtVerifier.verify(token);

            // 验证token是否在Redis中
            String redisKey = "token:" + role + ":" + userId;
            Object value = staticRedisTemplate.opsForValue().get(redisKey);
            Set<String> userTokens = new HashSet<>();
            if (value instanceof Set) {
                for (Object obj : (Set<?>) value) {
                    if (obj instanceof String) {
                        userTokens.add((String) obj);
                    }
                }
            }
            if (!userTokens.isEmpty() && userTokens.contains(token)) {
                // 刷新token过期时间
                staticRedisTemplate.expire(redisKey, 1, TimeUnit.DAYS);
                return false; // token有效
            }
            return true;
        } catch (Exception e) {
            return true;
        }
    }

    /**
     * 获取当前登录的用户
     */
    public static Account getCurrentUser() {
        HttpServletRequest request = ((ServletRequestAttributes) Objects
                .requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String token = request.getHeader("token");
        if (StrUtil.isBlank(token)) {
            token = request.getParameter("token");
        }

        if (verifyToken(token)) { // 验证token是否有效
            return null; // token无效，返回null
        }

        // 拿到token载荷数据
        String audience = JWT.decode(token).getAudience().get(0);
        String[] split = audience.split(":");
        String userId = split[0];
        String role = split[2];

        // 根据token解析出来的userId去对应的表查询用户信息
        if ("ADMIN".equals(role)) {
            return staticeAdminService.selectById(Integer.valueOf(userId));
        } else if ("TEACHER".equals(role)) {
            return staticeTeacherService.selectById(Integer.valueOf(userId));
        } else if ("STUDENT".equals(role)) {
            return staticeStudentService.selectById(Integer.valueOf(userId));
        }
        return null;
    }

    /**
     * 注销指定设备的token
     */
    public static void logout(String userId, String role, String token) {
        String redisKey = "token:" + role + ":" + userId;
        Optional.of(getUserTokens(redisKey))
                .ifPresentOrElse(userTokens -> {
                    userTokens.remove(token);
                    if (userTokens.isEmpty()) {
                        staticRedisTemplate.delete(redisKey);
                    } else {
                        staticRedisTemplate.opsForValue().set(redisKey, userTokens, 1, TimeUnit.DAYS);
                    }
                }, () -> {
                    // 如果 userTokens 为空或不存在，直接返回
                });
    }

    /**
     * 检查用户当前设备登录数
     */
    public static int getUserDeviceCount(String userId, String role) {
        String redisKey = "token:" + role + ":" + userId;
        Set<String> userTokens = getUserTokens(redisKey);
        return userTokens.size();
    }

    /**
     * 注销用户的所有设备token
     */
    public static void logoutAll(String userId, String role) {
        String redisKey = "token:" + role + ":" + userId;
        staticRedisTemplate.delete(redisKey);
    }
}
